#ifndef __COURSE_CPP__
#define __COURSE_CPP__
#include "../include/course.h"
#include "../include/printer.h"


void Course::print() {
    // wprintf(L"课程号: %.8d  学分: %3.1f  课程名: %-16ls\n",
    //     cno, credit, cname);
    // C++ 的 ostream 非常痛苦...
    // std::wcout << std::fixed
    //     << L"课程号: " << std::setw(8) << std::setfill(L'0') << cno
    //     << L"  学分: " << std::setprecision(1) << credit
    //     << L"  课程名: " << std::left << std::setw(16) << std::setfill(L' ')
    //     << cname << std::resetiosflags(std::ios::left)
    //     << std::resetiosflags(std::ios::fixed) << std::endl;
    // C++20 format 好!
    Printer::fmtln(L"课程号: {:0>8d}  学分: {:.1f}  课程名: {: <16s}",
        cno, credit, cname);
}
bool Course::scan() {
    std::wstring wstr;
    std::wcout << L"(课程名) ";
    std::getline(std::wcin, wstr);
    if (wstr.empty()) {
        return false;
    }
    // 输入超长的部分会被丢弃, 并添加'\0'
    wcsncpy(cname, wstr.c_str(), sizeof(cname) / sizeof(*cname) - 1);
    std::wcout << L"(学分)   ";
    std::wcin >> credit;
    std::wcin.ignore(10000, '\n');
    return true;
}

void Course::rescan() {
    this->print();
    std::wstring input;
    std::wcout << L"输入空行则保留原来的信息." << std::endl;
    std::wcout << L"(课程名) ";
    std::getline(std::wcin, input);
    if (!input.empty()) {
        wcsncpy(cname, input.c_str(),
            sizeof(Course::cname) / sizeof(*Course::cname) - 1);
    }
    std::wcout << L"(学分)   ";
    std::getline(std::wcin, input);
    if (!input.empty()) {
        credit = stof(input);
    }
}

bool Course::found(
    std::vector<std::wstring>& strs,
    std::vector<int>& code) {

    bool can = true;
    std::partial_ordering res;

    // 浮点数判断 相等 需要指定精度.
    auto fcmp = [](float a, float b) {
        if (fabs(a - b) < 0.0001) a = b;
        return a <=> b;
    };

    // 将 wcscmp() 的比较结果包装为 wchar_t * 的 <=> 运算符. (C++20 的新东西)
    // 直接对 wchar_t * 使用 <=> 会比较指针大小, 这不是预期行为.
    // 试过直接对 std::wstring 运用 <=> , 报错了...
    auto scmp = [](const wchar_t * s1, const wchar_t * s2) {
        return wcscmp(s1, s2) <=> 0;
    };

    for (int i = 0; code[i] && can; i += 3) {
        // 这些魔法数字的说明请看 parse<Course>() 的注释.
        if (code[i] == 0x01) { res = scmp(cname, strs[code[i + 2]].c_str()); }
        if (code[i] == 0x02) { res = cno <=> code[i + 2]; }
        if (code[i] == 0x03) { res = fcmp(credit, *(float*)(&code[i + 2])); }

        switch (code[i + 1]) {
        case 0x11: if (res == 0) continue; goto NG;
        case 0x12: if (res != 0) continue; goto NG;
        case 0x13: if (res <  0) continue; goto NG;
        case 0x14: if (res <= 0) continue; goto NG;
        case 0x15: if (res >  0) continue; goto NG;
        case 0x16: if (res >= 0) continue; goto NG;
        }
        NG:
        can = false;
    }
    return can;
}


#endif /* __COURSE_CPP__ */
